#include <types.h>
#include <sys_config.h>

#include <api/libtsi/si_types.h>
#include <api/libtsi/si_descriptor.h>

#include <api/libsi/desc_loop_parser.h>

struct descriptor {
	UINT8 tag;
	UINT8 len;
	UINT8 data[0];
}__attribute__((packed));

/**
 * desc_loop_parser, use to find descriptor's appropriate parser
 * @param data, descriptor loop's begin data buffer
 * @param len, descriptor loop's data length
 * @param descriptor_table, the descriptor list that caller want to process
 * @param desc_num_in_table, the count of element in descriptor_table
 * @return SI_SUCCESS, no appropriate parser, or no parser return !SI_SUCCESS value;
 *         otherwise, return other value when parser return !SI_SUCCESS.
 */
INT32 desc_loop_parser(UINT8 *data, INT32 len, struct desc_table *descriptor_table,
	INT32 desc_num_in_table, UINT32 *stat, void *priv)
{
	INT16 i, k;
	INT32 desc_len, ret;
	struct descriptor *desc;

	for(i=0; i<len; i += sizeof(struct descriptor)+desc_len) {
		desc = (struct descriptor *)(data+i);
		desc_len = desc->len;
		
		/* Use SEQUENTIAL SEARCH is more safer because BINARY SEARCH rely on the tag value
		 * INCREASE in descriptor_table, but not all this function's users know about this.
		 * And, the number of elements in descriptor table always small. */
		for (k=0; k<desc_num_in_table; k++) {
			
			/* check current descriptor received whether is a wanted one in table */
			if (desc->tag == descriptor_table[k].tag) {
				if (stat) {
					*stat |= (1<<descriptor_table[k].bit);
				}
				if (descriptor_table[k].parser) {	
					ret = descriptor_table[k].parser(desc->tag, 
						desc->len, desc->data, priv);
					if (ret != SI_SUCCESS)
						return ret;
				}
			}
		}
	}
	return SI_SUCCESS;
}

INT32 si_descriptor_parser(UINT8 *data, INT32 length, struct descriptor_info *info, INT32 nr)
{
	INT32 pos, i, k, ret;
	struct descriptor *desc;
	for(pos = 0; pos<length; pos+= desc->len+sizeof(struct descriptor)) {
		desc = (struct descriptor *)(data+pos);
		for(k=0; k<nr; k++) {
			if ((desc->tag == info[k].descriptor_tag)
				&&(info[k].mask_len<=desc->len)){
				for(i=0; i<info[k].mask_len; i++) {
					if ((desc->data[i]&info[k].mask[i]) != (info[k].value[i]&info[k].mask[i]))
						break;
				}
				if (i==info[k].mask_len) {
					ret = info[k].on_descriptor(desc->tag, 
						desc->len, desc->data, info->priv);
					if (ret != SI_SUCCESS) 
						return ret;
					break; /* k */
				} 
			}
		}
	}
	return SI_SUCCESS;
}


